package io.github.yotta.logger.core.support;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import io.github.yotta.logger.core.model.OpParam;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * @author yotta
 * @date 2025/3/13 16:17
 */
public class ParamResolver {

    private static final ParameterNameDiscoverer parameterNameDiscoverer;

    static {
        parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
    }


    public static Object resolve(Method method, String bizIdPath, Object[] argValues) {
        String[] argNames = parameterNameDiscoverer.getParameterNames(method);
        if (argNames == null || argNames.length == 0) return null;
        Object value = null;
        String[] splits = bizIdPath.split("\\.");
        int paramIndex = 0;
        for (int i = 0; i < argNames.length; i++) {
            if (argNames[i].equals(splits[0])) {
                paramIndex = i;
                break;
            }
        }
        if (0 == splits.length - 1) {
            value = argValues[paramIndex];
            return value;
        }
        String join = StringUtils.join(Arrays.copyOfRange(splits, 1, splits.length), "?.");
        value = resolveParam(argValues[paramIndex], join);
        return value;
    }

    public static Object resolve(String bizIdPath, Object argValues) {
        return resolveParam(argValues, bizIdPath);
    }

    /**
     * param.id
     */
    private static Object resolveParam(Object argValue, String bizIdPath) {
        ExpressionParser parser = new SpelExpressionParser();
        // 将value设置为RootObject
        EvaluationContext context = new StandardEvaluationContext(argValue);
        return parser.parseExpression(bizIdPath).getValue(context);
    }

    public static List<OpParam> resolveParam(Method method, Object[] argValues) {
        if (argValues == null || argValues.length == 0) {
            return Collections.emptyList();
        }
        String[] argNames = parameterNameDiscoverer.getParameterNames(method);
        List<OpParam> params = Lists.newArrayListWithCapacity(argValues.length);
        for (int i = 0; i < Objects.requireNonNull(argNames).length; i++) {
            OpParam opParam = new OpParam();
            Object argValue = argValues[i];
            Class<?> aClass = argValue.getClass();
            opParam.setIsPrimitive(isPrimitive(argValue));
            opParam.setName(argNames[i]);
            opParam.setValue(JSON.toJSONString(argValue));
            opParam.setClassName(aClass.getName());
            params.add(opParam);
        }
        return params;
    }


    private static boolean isPrimitive(Object value) {
        if (value == null) {
            return false;
        }
        Class<?> clazz = value.getClass();
        // 检查是否为基本类型的包装类
        if (clazz.equals(Integer.class) || clazz.equals(Long.class) ||
                clazz.equals(Double.class) || clazz.equals(Float.class) ||
                clazz.equals(Character.class) || clazz.equals(Short.class) ||
                clazz.equals(Byte.class) || clazz.equals(Boolean.class) ||
                clazz.equals(String.class) || clazz.equals(Void.class) ||
                clazz.equals(BigDecimal.class)

        ) {
            return true;
        }
        // 尝试匹配基本类型
        if (clazz.isPrimitive()) {
            return true;
        }
        // 另一种方式是检查包装类的TYPE字段，但这仅适用于包装类型
        try {
            return ((Class<?>) clazz.getField("TYPE").get(null)).isPrimitive();
        } catch (NoSuchFieldException | IllegalAccessException ignored) {
            // 忽略异常，非包装类型没有TYPE字段
        }
        return false;
    }


}
